# -*- coding: utf-8 -*-
import json
import logging
from datetime import timedelta, datetime

from common.account.db.account import get_account
from common.cache.redis_cache import get_award_ranking, get_user_award_ranking, set_award_ranking, \
    set_user_award_ranking
from common.campaign.model.winner_ranking import WINNER_AWARD_TYPE, AWARD_CONFIG, AWARD_POOL_RATIO
from common.preset.db.banner import get_banner_by_type
from common.preset.model.preset import BANNER_TYPE
from common.stats import MG_BIGBANG_COLL
from common.utils.exceptions import ConfigError
from common.utils.tz import now_ts, today_str, utc_to_local, left_seconds_today

_LOGGER = logging.getLogger('bigbang')


def get_winner_pool(start, end):
    cond = {
        "_id": {
            "$gte": start,
            "$lt": end
        }
    }
    bigbang_cursor = MG_BIGBANG_COLL.daily_report.aggregate([
        {"$match": cond},
        {"$group": {"_id": None, "total_pay": {"$sum": "$pay_price"}}}
    ])
    bigbang_pay = bigbang_cursor.next().get('total_pay', 0) if bigbang_cursor.alive else 0

    kfc_cursor = MG_BIGBANG_COLL.kfc_report.aggregate([
        {"$match": cond},
        {"$group": {"_id": None, "total_pay": {"$sum": "$bet_amount"}}}
    ])
    kfc_pay = kfc_cursor.next().get('total_pay', 0) if kfc_cursor.alive else 0

    lottery_cursor = MG_BIGBANG_COLL.lottery_report.aggregate([
        {"$match": cond},
        {"$group": {"_id": None, "total_pay": {"$sum": "$bet_amount"}}}
    ])
    lottery_pay = lottery_cursor.next().get('total_pay', 0) if lottery_cursor.alive else 0

    bull_cursor = MG_BIGBANG_COLL.bull_report.aggregate([
        {"$match": cond},
        {"$group": {"_id": None, "total_pay": {"$sum": "$bet_amount"}}}
    ])
    bull_pay = bull_cursor.next().get('total_pay', 0) if bull_cursor.alive else 0

    fruit_cursor = MG_BIGBANG_COLL.fruit_report.aggregate([
        {"$match": cond},
        {"$group": {"_id": None, "total_pay": {"$sum": "$bet_amount"}}}
    ])
    fruit_pay = fruit_cursor.next().get('total_pay', 0) if fruit_cursor.alive else 0
    return float(bigbang_pay) + float(kfc_pay) + float(bull_pay) + float(fruit_pay) + float(lottery_pay)


def get_campaign_status(user_id):
    banner = get_banner_by_type(BANNER_TYPE.WINNER_RANKING)
    if not banner:
        return {
            'status': 'not_available',
        }
    if now_ts() > banner.campaign_end:
        return {
            'status': 'ended',
        }
    if now_ts() < banner.campaign_start:
        return {
            'status': 'not_started',
            'left_seconds': banner.campaign_start - now_ts()
        }
    if banner.start_ts <= now_ts() <= banner.campaign_end:

        award_ranking = get_award_ranking()
        if not award_ranking:
            award_ranking = {
                'daily': get_daily_ranking(),
                'weekly': get_weekly_ranking(),
                'total': get_total_ranking(),
            }
            set_award_ranking(json.dumps(award_ranking))
        else:
            award_ranking = json.loads(award_ranking)

        result = {
            'status': 'ongoing',
            'ranking': award_ranking,
            'award_countdown': {
                'daily': get_daily_countdown(),
                'weekly': get_weekly_countdown(),
                'total': get_total_countdown(),
            },
        }
        if user_id:
            user_ranking = get_user_award_ranking(user_id)
            if not user_ranking:
                user_ranking = {
                    'daily': get_daily_user_data(user_id),
                    'weekly': get_weekly_user_data(user_id),
                    'total': get_total_user_data(user_id),
                }
                set_user_award_ranking(user_id, json.dumps(user_ranking))
            else:
                user_ranking = json.loads(user_ranking)

            result['user_data'] = user_ranking
        return result


def get_daily_ranking():
    start = utc_to_local(datetime.utcnow()).replace(hour=0, minute=0, second=0, microsecond=0)
    end = utc_to_local(datetime.utcnow()).replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
    _LOGGER.info('daily ranking start is %s, end is %s' % (start, end))
    return get_winner_ranking(start, end, WINNER_AWARD_TYPE.DAILY)


def get_daily_pool(start_date):
    start = utc_to_local(start_date)
    end = utc_to_local(start_date + timedelta(days=1))
    return round(get_winner_pool(start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d')) * 0.25 * AWARD_POOL_RATIO, 3)


def get_weekly_ranking():
    banner = get_banner_by_type(BANNER_TYPE.WINNER_RANKING)
    campaign_start = datetime.fromtimestamp(banner.campaign_start)
    now = datetime.now()
    delta_time = (now - campaign_start).days / 7 * 7
    start = campaign_start + timedelta(days=delta_time)
    end = now
    return get_winner_ranking(start, end, WINNER_AWARD_TYPE.WEEKLY)


def get_weekly_pool(start_date):
    start = utc_to_local(start_date)
    end = utc_to_local(start_date + timedelta(days=7))
    return round(get_winner_pool(start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d')) * 0.15 * AWARD_POOL_RATIO, 3)


def get_total_ranking():
    banner = get_banner_by_type(BANNER_TYPE.WINNER_RANKING)
    start = datetime.fromtimestamp(banner.campaign_start)
    end = datetime.fromtimestamp(banner.campaign_end)
    return get_winner_ranking(start, end, WINNER_AWARD_TYPE.TOTAL)


def get_total_pool():
    banner = get_banner_by_type(BANNER_TYPE.WINNER_RANKING)
    start = utc_to_local(datetime.fromtimestamp(banner.campaign_start))
    end = utc_to_local(datetime.fromtimestamp(banner.campaign_end))
    return round(get_winner_pool(start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d')) * 0.60 * AWARD_POOL_RATIO, 3)


def get_daily_countdown():
    return left_seconds_today()


def get_weekly_countdown():
    banner = get_banner_by_type(BANNER_TYPE.WINNER_RANKING)
    campaign_start = datetime.fromtimestamp(banner.campaign_start)
    now = datetime.now()
    delta_time = timedelta(days=((now - campaign_start).days / 7 + 1) * 7)
    return int((campaign_start + delta_time - now).total_seconds())


def get_total_countdown():
    banner = get_banner_by_type(BANNER_TYPE.WINNER_RANKING)
    now = datetime.now()
    end = datetime.fromtimestamp(banner.campaign_end)
    return int((end - now).total_seconds())


def get_winner_ranking(start, end, award_type):
    cond = {
        "updated_at": {
            "$gte": start,
            "$lt": end
        }
    }
    cursor = MG_BIGBANG_COLL.daily_stats.aggregate([
        {"$match": cond},
        {"$project": {
            "user_id": 1,
            "win": {"$ifNull": ["$win.total", 0]},
            "bonus": {"$ifNull": ["$bonus.total", 0]},
            "kfc": {"$ifNull": ["$kfc.win_amount", 0]},
            "lottery": {"$ifNull": ["$lottery.win_amount", 0]},
            "fruit": {"$ifNull": ["$fruit.win_amount", 0]},
            "bull": {"$ifNull": ["$bull.win_amount", 0]},
        }},
        {"$project": {"user_id": 1,
                      "total": {"$add": ["$win",
                                         "$bonus",
                                         "$lottery",
                                         "$kfc",
                                         "$fruit",
                                         "$bull"
                                         ]}}},
        {"$group": {"_id": "$user_id", "total": {"$sum": "$total"}}},
        {"$sort": {"total": -1}},
        {"$limit": 100},
    ])

    award_pool = 0
    if award_type == WINNER_AWARD_TYPE.DAILY:
        award_pool = get_daily_pool(datetime.utcnow())
    if award_type == WINNER_AWARD_TYPE.WEEKLY:
        award_pool = get_weekly_pool(start)
    if award_type == WINNER_AWARD_TYPE.TOTAL:
        award_pool = get_total_pool()

    ranking = []
    rank = 1
    for item in list(cursor):
        user_id = int(item['_id'])
        account = get_account(user_id)
        if not account:
            continue
        if not item['total']:
            continue
        ranking.append({
            'rank': rank,
            'user_id': user_id,
            'username': account.user_name[:2] + u'***' + account.user_name[-2:],
            'amount': round(float(item['total']), 3),
            'estimated_award': round(float(award_pool) * get_award_ratio(rank, award_type), 3)
        })
        rank += 1
    return ranking


def get_award_ratio(rank, award_type):
    award_config = AWARD_CONFIG.get(award_type)
    if not award_config:
        raise ConfigError('award type <%s> not in AWARD_CONFIG' % award_type)
    if award_type == WINNER_AWARD_TYPE.DAILY:
        if rank <= 10:
            return award_config.get(rank)
        elif rank <= 100:
            return award_config.get('default')
        else:
            return 0
    else:
        if rank <= 10:
            return award_config.get(rank)
        else:
            return 0


def get_daily_user_data(user_id):
    start = utc_to_local(datetime.utcnow()).replace(hour=0, minute=0, second=0, microsecond=0)
    end = start + timedelta(days=1)
    return get_user_data(user_id, start, end, WINNER_AWARD_TYPE.DAILY)


def get_weekly_user_data(user_id):
    banner = get_banner_by_type(BANNER_TYPE.WINNER_RANKING)
    campaign_start = datetime.fromtimestamp(banner.campaign_start)
    now = datetime.now()
    delta_time = (now - campaign_start).days / 7 * 7
    start = campaign_start + timedelta(days=delta_time)
    end = now
    return get_user_data(user_id, start, end, WINNER_AWARD_TYPE.WEEKLY)


def get_total_user_data(user_id):
    banner = get_banner_by_type(BANNER_TYPE.WINNER_RANKING)
    start = datetime.fromtimestamp(banner.campaign_start)
    end = datetime.fromtimestamp(banner.campaign_end)
    return get_user_data(user_id, start, end, WINNER_AWARD_TYPE.TOTAL)


def get_user_data(user_id, start, end, award_type):
    cond = {
        "updated_at": {
            "$gte": start,
            "$lt": end
        }
    }
    cursor = MG_BIGBANG_COLL.daily_stats.aggregate([
        {"$match": cond},
        {"$project": {
            "user_id": 1,
            "win": {"$ifNull": ["$win.total", 0]},
            "bonus": {"$ifNull": ["$bonus.total", 0]},
            "kfc": {"$ifNull": ["$kfc.win_amount", 0]},
            "lottery": {"$ifNull": ["$lottery.win_amount", 0]},
            "fruit": {"$ifNull": ["$fruit.win_amount", 0]},
            "bull": {"$ifNull": ["$bull.win_amount", 0]},
        }},
        {"$project": {"user_id": 1,
                      "total": {"$add": ["$win",
                                         "$bonus",
                                         "$lottery",
                                         "$kfc",
                                         "$fruit",
                                         "$bull"
                                         ]}}},
        {"$group": {"_id": "$user_id", "total": {"$sum": "$total"}}},
        {"$sort": {"total": -1}},
    ])
    award_pool = 0
    if award_type == WINNER_AWARD_TYPE.DAILY:
        award_pool = get_daily_pool(datetime.utcnow())
    if award_type == WINNER_AWARD_TYPE.WEEKLY:
        award_pool = get_weekly_pool(start)
    if award_type == WINNER_AWARD_TYPE.TOTAL:
        award_pool = get_total_pool()
    rank = 1
    for item in list(cursor):
        if int(item['_id']) == int(user_id):
            if not item['total']:
                return {
                    'rank': None,
                    'amount': None
                }
            return {
                'rank': rank,
                'amount': round(float(award_pool) * get_award_ratio(rank, award_type), 3) 
                # 'estimated_award': round(float(award_pool) * get_award_ratio(rank, award_type), 3) 
            }
        rank += 1
    return {
        'rank': None,
        'amount': None
    }
